%{
#include "p-machine.hh"
#include "data_structures.hh"
#include <stdio.h>
#include <list>
extern int yylex();
extern void yyerror(const char *);
extern FILE *yyin;
std::list<int> code;
//??? typedef yy_buffer_state *YY_BUFFER_STATE;
//??? extern YY_BUFFER_STATE yy_scan_string(const char *);
%}

%token EOL
%token TRUE FALSE INT NOT
%token OBJ1
%token AVAIL CARRIED POSOF
%token DO IF HERE LONG THEN VISITED SHORT OBJECTS EXITS NEWLINE INVENTORY MSG

%%

expressions:	expression
		| expression '\n'
		| expressions expression
		;

expression:	DO actions { printf("\nActions only!\n"); }
		| cond_check actions { printf("\nIs valid!\n"); }
		;

cond_check:	IF bool_exprs THEN { code.push_back(pcode_end_on_false); }

bool_exprs:	bool_expr
		| NOT bool_expr { code.push_back(pcode_lnot); }
		;

bool_expr:	cond_eq | cond_lt | cond_gt | cond_visited | cond_carried | cond_avail

cond_eq:	value '=' value { code.push_back(pcode_cmp_eq); }
cond_lt:	value '<' value { code.push_back(pcode_cmp_lt); }
cond_gt:	value '>' value { code.push_back(pcode_cmp_gt); }
cond_visited:	VISITED { code.push_back(pcode_load_here);
			  code.push_back(pcode_load_visited); }
cond_carried:	CARRIED objnum { std::list<int> newc = { pcode_load_obj_pos, pcode_load_immediate, (short)POS_CARRIED, pcode_cmp_eq };
			       	 code.splice(code.end(), newc); }
cond_avail:	AVAIL objnum { std::list<int> newc = { pcode_load_obj_pos, pcode_dup, pcode_load_immediate, (short)POS_CARRIED, pcode_cmp_eq, pcode_exchange, pcode_load_here, pcode_cmp_eq, pcode_and };
			       	 code.splice(code.end(), newc); }

objnum:		immediate
		| OBJ1 { code.push_back(pcode_load_obj1); }
		;

value:		objnum
		| HERE { code.push_back(pcode_load_here); }
		| POSOF immediate { code.push_back(pcode_load_obj_pos); }
		;

immediate:	INT { std::list<int> newc = { pcode_load_immediate, $1 };
		      code.splice(code.end(), newc); }

actions: action ';'
	| actions action ';'
	;

action:	LONG { code.push_back(pcode_look_long); }
	| SHORT { code.push_back(pcode_look_short); }
	| EXITS { code.push_back(pcode_print_exits); }
	| OBJECTS { code.push_back(pcode_print_objs); }
	| NEWLINE { code.push_back(pcode_nl); }
	| INVENTORY { code.push_back(pcode_inventory); }
	| MSG value { code.push_back(pcode_write_mesg); }
	| TRUE { code.push_back(pcode_load_true); }
	| FALSE { code.push_back(pcode_load_false); }
	;

%%

int main(int argc, char **argv) {
  do {
    char str[] = "if not carried 7 then msg 4; true;";
    char str2[] = "if carried 2 then msg 94; true;";
    yyin = fmemopen(str, sizeof(str), "r");
    yyparse();
    fclose(yyin);
    yyin = fmemopen(str2, sizeof(str), "r");
    //YY_FLUSH_BUFFER;
    yyparse();
    fclose(yyin);
    //??? yy_scan_string("if not carried 7 then msg 4; true;");
    printf("len(code)=%ld: ", (long)code.size());
    for(auto it = code.begin(); it != code.end(); ++it) {
      printf(" %04hx", *it);
    }
    putchar('\n');
  } while(!feof(yyin));
  return 0;
}

void yyerror(const char *s) {
  fprintf(stderr, "parse error: %s\n", s);
}
